package com.wl.shixun1.mymvc;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class MyDecimal implements Num {
    private BigDecimal value;

    public MyDecimal() {
        this.value = BigDecimal.ZERO;
    }

    public MyDecimal(BigDecimal value) {
        this.value = value;
    }

    public MyDecimal(double value) {
        this.value = BigDecimal.valueOf(value);
    }

    public MyDecimal(String value) {
        this.value = new BigDecimal(value);
    }

    public BigDecimal getValue() {
        return value;
    }

    public void setValue(BigDecimal value) {
        this.value = value;
    }

    @Override
    public Num add(Num x) {
        MyDecimal result = new MyDecimal();
        if (x instanceof MyInt) {
            // 小数与整数相加
            MyInt xx = (MyInt) x;
            result.value = this.value.add(new BigDecimal(xx.getF()));
        } else if (x instanceof Fraction) {
            // 小数与分数相加
            Fraction xx = (Fraction) x;
            BigDecimal fractionValue = new BigDecimal(xx.getF1()).divide(new BigDecimal(xx.getF2()), 10, RoundingMode.HALF_UP);
            result.value = this.value.add(fractionValue);
        } else {
            // 小数与小数相加
            MyDecimal xx = (MyDecimal) x;
            result.value = this.value.add(xx.value);
        }
        return result;
    }

    @Override
    public Num sub(Num x) {
        MyDecimal result = new MyDecimal();
        if (x instanceof MyInt) {
            // 小数与整数相减
            MyInt xx = (MyInt) x;
            result.value = this.value.subtract(new BigDecimal(xx.getF()));
        } else if (x instanceof Fraction) {
            // 小数与分数相减
            Fraction xx = (Fraction) x;
            BigDecimal fractionValue = new BigDecimal(xx.getF1()).divide(new BigDecimal(xx.getF2()), 10, RoundingMode.HALF_UP);
            result.value = this.value.subtract(fractionValue);
        } else {
            // 小数与小数相减
            MyDecimal xx = (MyDecimal) x;
            result.value = this.value.subtract(xx.value);
        }
        return result;
    }

    @Override
    public Num mul(Num x) {
        MyDecimal result = new MyDecimal();
        if (x instanceof MyInt) {
            // 小数与整数相乘
            MyInt xx = (MyInt) x;
            result.value = this.value.multiply(new BigDecimal(xx.getF()));
        } else if (x instanceof Fraction) {
            // 小数与分数相乘
            Fraction xx = (Fraction) x;
            BigDecimal fractionValue = new BigDecimal(xx.getF1()).divide(new BigDecimal(xx.getF2()), 10, RoundingMode.HALF_UP);
            result.value = this.value.multiply(fractionValue);
        } else {
            // 小数与小数相乘
            MyDecimal xx = (MyDecimal) x;
            result.value = this.value.multiply(xx.value);
        }
        return result;
    }

    @Override
    public Num div(Num x) {
        MyDecimal result = new MyDecimal();
        if (x instanceof MyInt) {
            // 小数除以整数
            MyInt xx = (MyInt) x;
            if (xx.getF() != 0) {
                result.value = this.value.divide(new BigDecimal(xx.getF()), 10, RoundingMode.HALF_UP);
            } else {
                throw new ArithmeticException("除数不能为零");
            }
        } else if (x instanceof Fraction) {
            // 小数除以分数
            Fraction xx = (Fraction) x;
            if (xx.getF1() != 0) {
                BigDecimal fractionValue = new BigDecimal(xx.getF1()).divide(new BigDecimal(xx.getF2()), 10, RoundingMode.HALF_UP);
                result.value = this.value.divide(fractionValue, 10, RoundingMode.HALF_UP);
            } else {
                throw new ArithmeticException("除数不能为零");
            }
        } else {
            // 小数除以小数
            MyDecimal xx = (MyDecimal) x;
            if (!xx.value.equals(BigDecimal.ZERO)) {
                result.value = this.value.divide(xx.value, 10, RoundingMode.HALF_UP);
            } else {
                throw new ArithmeticException("除数不能为零");
            }
        }
        return result;
    }

    @Override
    public String draw1() {
        // 格式化输出，去掉末尾的0
        return this.value.stripTrailingZeros().toPlainString();
    }
    
    // 实现三个数的表达式计算，根据运算符优先级进行计算
    @Override
    public Num calculateExpression(Num num2, Num num3, String op1, String op2) {
        // 先判断运算符优先级
        if ((op1.equals("mul") || op1.equals("div")) && (op2.equals("add") || op2.equals("sub"))) {
            // 如果第一个运算符是乘除，第二个是加减，则先计算第一个
            Num temp = this;
            switch (op1) {
                case "mul":
                    temp = this.mul(num2);
                    break;
                case "div":
                    temp = this.div(num2);
                    break;
                case "add":
                    temp = this.add(num2);
                    break;
                case "sub":
                    temp = this.sub(num2);
                    break;
            }
            
            // 然后计算第二个运算符
            switch (op2) {
                case "mul":
                    return temp.mul(num3);
                case "div":
                    return temp.div(num3);
                case "add":
                    return temp.add(num3);
                case "sub":
                    return temp.sub(num3);
            }
        } else if ((op2.equals("mul") || op2.equals("div")) && (op1.equals("add") || op1.equals("sub"))) {
            // 如果第二个运算符是乘除，第一个是加减，则先计算第二个
            Num temp = num2;
            switch (op2) {
                case "mul":
                    temp = num2.mul(num3);
                    break;
                case "div":
                    temp = num2.div(num3);
                    break;
                case "add":
                    temp = num2.add(num3);
                    break;
                case "sub":
                    temp = num2.sub(num3);
                    break;
            }
            
            // 然后计算第一个运算符
            switch (op1) {
                case "mul":
                    return this.mul(temp);
                case "div":
                    return this.div(temp);
                case "add":
                    return this.add(temp);
                case "sub":
                    return this.sub(temp);
            }
        } else {
            // 如果运算符优先级相同，则从左到右计算
            Num temp = this;
            switch (op1) {
                case "mul":
                    temp = this.mul(num2);
                    break;
                case "div":
                    temp = this.div(num2);
                    break;
                case "add":
                    temp = this.add(num2);
                    break;
                case "sub":
                    temp = this.sub(num2);
                    break;
            }
            
            // 然后计算第二个运算符
            switch (op2) {
                case "mul":
                    return temp.mul(num3);
                case "div":
                    return temp.div(num3);
                case "add":
                    return temp.add(num3);
                case "sub":
                    return temp.sub(num3);
            }
        }
        
        return null;
    }
}